package com.imagination.applet.domain.photo.service.impl;

import com.google.common.collect.Lists;
import com.imagination.applet.controller.api.request.cropReq;
import com.imagination.applet.controller.web.configuration.UserHolder;
import com.imagination.applet.domain.adapter.os.OSSAdapter;
import com.imagination.applet.domain.photo.model.PhotoType;
import com.imagination.applet.domain.photo.model.UserPhoto;
import com.imagination.applet.domain.photo.model.UserPhotoConstant;
import com.imagination.applet.domain.photo.model.UserPhotosResult;
import com.imagination.applet.domain.photo.repository.UserPhotoMetricRepository;
import com.imagination.applet.domain.photo.repository.UserPhotoRepository;
import com.imagination.applet.domain.photo.service.UserPhotoCommandService;
import com.imagination.applet.domain.photo.service.UserPhotoQueryService;
import com.imagination.applet.domain.utils.ImagePathGenerator;
import com.imagination.applet.infrastructure.handler.BadRequestException;
import com.imagination.applet.infrastructure.handler.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class UserPhotoServiceImpl implements UserPhotoQueryService, UserPhotoCommandService {
    private final UserPhotoRepository userPhotoRepository;
    private final UserPhotoMetricRepository userPhotoMetricRepository;

    private final OSSAdapter ossAdapter;

    @Override
    public UserPhotosResult addPhotos(Long userId, List<MultipartFile> photos, cropReq cropReq) {
        List<String> success = Lists.newArrayList();
        photos.forEach(
                file -> {
                    final String key = UserPhoto.PREFIX_PATH + ImagePathGenerator.next(file.getOriginalFilename());
                    try {
                        ossAdapter.putObject(key, file.getInputStream());
                        success.add(key);
                    } catch (Exception e) {
                        log.warn("Failed to upload photo, userId: {}, photo : {}", userId, file.getOriginalFilename());
                    }
                }
        );
        if (CollectionUtils.isEmpty(success)) {
            throw new BusinessException(UserPhotoConstant.NO_PHOTOS_AVAILABLE, "没有可用对照片");
        }
        saveUserPhotos(userId, success, cropReq);
        List<UserPhoto> list = userPhotoRepository.queryByUserIdAndDeletedIsFalse(userId);
        return UserPhotosResult.ok(list, success);
    }

    @Override
    public List<UserPhoto> userPhotos() {
        Long userId = UserHolder.getUserIdNotException();
        if(userId==null){
            return new ArrayList<>();
        }
        return userPhotoRepository.queryByUserIdAndDeletedIsFalseAndType(userId, 0);
    }

    @Override
    @Transactional
    public void removePhoto(Long userId, Long photoId) {
        queryUserPhoto(userId, photoId);
        // userPhotoRepository.deleteByPhotoId(photoId);
        userPhotoRepository.deleteById(photoId);
    }

    @Override
    public int removePhotos(Long userId, List<Long> photoIdList) {
        return userPhotoRepository.deleteByPhotoId(photoIdList);
    }

    @Override
    public UserPhotosResult queryUserPhotos(Long userId) {
        List<UserPhoto> photos = userPhotoRepository.queryByUserIdAndDeletedIsFalse(userId);
        return UserPhotosResult.of(photos);
    }

    @Override
    public UserPhoto queryUserPhoto(Long userId, Long photoId) {
        Optional<UserPhoto> optional = userPhotoRepository.findById(photoId);
        optional.ifPresentOrElse(p -> {
                    if (!userId.equals(p.getUserId())) {
                        String error = String.format("Not exist photo, photoId : %s", photoId);
                        throw new BadRequestException(error);
                    }
                },
                () -> {
                    throw new BadRequestException(String.format("Can't use non own photo, userId : %d, photoUserId : %d", userId, photoId));
                }
        );
        return optional.get();
    }

    @Override
    public List<UserPhoto> queryUserPhotos(Long userId, List<Long> photoIdList) {
        List<UserPhoto> allById = userPhotoRepository.findAllById(photoIdList);
        allById.forEach(e -> {
            if (!userId.equals(e.getUserId())) {
                String error = String.format("Not exist photo, photoId : %s", e.getId());
                throw new BadRequestException(error);
            }
        });
        return allById;
    }

    private UserPhoto save(final Long userId, final String key, cropReq cropReq) {
        UserPhoto photo = UserPhoto.builder()
                .userId(userId)
                .photoType(PhotoType.VIRTUAL_IDENTITY)
                .photoPath(key)
                .type(cropReq.getType())
                .available(true)
                .build();
        return userPhotoRepository.save(photo);
    }

    private void saveUserPhotos(final Long userId, final List<String> key, cropReq cropReq) {
        key.forEach(k -> {
            save(userId, k, cropReq);
        });
        userPhotoRepository.flush();
    }
}
